use actix_web::{HttpResponse, ResponseError};
use thiserror::Error;
use uuid::Uuid;

#[derive(Error, Debug)]
pub enum AppError {
    #[error("Database error: {0}")]
    Database(#[from] sea_orm::DbErr),
    
    #[error("JWT error: {0}")]
    JwtError(#[from] jsonwebtoken::errors::Error),
    
    #[error("IO error: {0}")]
    IoError(#[from] std::io::Error),
    
    #[error("Multipart error: {0}")]
    MultipartError(#[from] actix_multipart::MultipartError),
    
    #[error("Validation error: {0}")]
    Validation(String),
    
    #[error("Not found: {entity} with id {id}")]
    NotFound { entity: String, id: Uuid },
    
    #[error("Unauthorized: {0}")]
    Unauthorized(String),
    
    #[error("Forbidden: {0}")]
    Forbidden(String),
    
    #[error("JWT error: {0}")]
    Jwt(String),
    
    #[error("OIDC error: {0}")]
    Oidc(String),
    
    #[error("Cache error: {0}")]
    Cache(String),
    
    #[error("Internal server error: {0}")]
    Internal(String),
}

impl ResponseError for AppError {
    fn error_response(&self) -> HttpResponse {
        match self {
            AppError::Validation(msg) => HttpResponse::BadRequest().json(serde_json::json!({
                "error": "validation_error",
                "message": msg
            })),
            
            AppError::NotFound { entity, id } => HttpResponse::NotFound().json(serde_json::json!({
                "error": "not_found",
                "entity": entity,
                "id": id.to_string()
            })),
            
            AppError::Unauthorized(msg) => HttpResponse::Unauthorized().json(serde_json::json!({
                "error": "unauthorized",
                "message": msg
            })),
            
            AppError::Forbidden(msg) => HttpResponse::Forbidden().json(serde_json::json!({
                "error": "forbidden",
                "message": msg
            })),
            
            AppError::Jwt(_) | AppError::Oidc(_) => HttpResponse::Unauthorized().json(serde_json::json!({
                "error": "authentication_error",
                "message": "Invalid or expired token"
            })),
            
            _ => HttpResponse::InternalServerError().json(serde_json::json!({
                "error": "internal_server_error",
                "message": "An unexpected error occurred"
            })),
        }
    }
}

pub type Result<T> = std::result::Result<T, AppError>;